package com.huayue.user.service;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.huayue.user.api.UserServiceApi;
import com.huayue.user.bean.UserDto;
import com.huayue.user.bean.UserPo;
import com.huayue.user.exception.IncorrectPasswordException;
import com.huayue.user.exception.ParamException;
import com.huayue.user.exception.UserAlreadyExistException;
import com.huayue.user.exception.UserNotExistException;
import com.huayue.user.mapper.UserMapper;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.beans.factory.annotation.Autowired;
import java.sql.Timestamp;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

@Service
public class UserService implements UserServiceApi {
    @Autowired
    private UserMapper userMapper;

    @Override
    public UserDto add(String name, String no, String password) throws UserAlreadyExistException, ParamException {
        //判断用户是否已存在
        UserDto userDto = queryByNo(no);
        if (userDto != null) {
            throw new UserAlreadyExistException("User already exist.");
        }
        //未存在则添加一条记录到数据库
        UserPo userPo = new UserPo();
        userPo.setNo(no);
        userPo.setAdmin(0);
        userPo.setName(name);
        userPo.setPassword(password);
        userPo.setUpdateTime(new Timestamp(System.currentTimeMillis()));
        userMapper.insert(userPo);
        userDto = queryByNo(no);
        return userDto;
    }

    /**
     * 校验参数是否为null
     * @param params
     * @throws ParamException
     */
    private void checkParam(Object ... params) throws ParamException {
        for (Object param : params) {
            if (param == null) {
                throw new ParamException("Exist param is null");
            }
        }
    }

    /**
     * 根据某个字段批量查询
     * @param column 条件字段
     * @param values 条件值
     * @return
     */
    private <T> Collection<UserDto> batchQuery(SFunction<UserPo, ?> column, Collection<T> values) throws ParamException {
        checkParam(values);
        LambdaQueryWrapper<UserPo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(column, values);
        List<UserPo> userPos = userMapper.selectList(queryWrapper);
        return JSON.parseObject(JSON.toJSONString(userPos),new TypeReference<List<UserDto>>(){});
    }

    /**
     * 查询单条记录
     * @param column
     * @param value
     * @return
     */
    private UserDto queryOne(SFunction<UserPo, ?> column, Object value) throws ParamException {
        checkParam(value);
        Collection<UserDto> userDtos = batchQuery(column, Arrays.asList(value));
        return userDtos.size() > 0 ? userDtos.iterator().next() : null;
    }

    /**
     * po转dto
     * @param userPo
     * @return
     */
    private UserDto convert(UserPo userPo) {
        return JSON.parseObject(JSON.toJSONString(userPo),UserDto.class);
    }

    @Override
    public Collection<UserDto> queryByNo(Collection<String> noList) throws ParamException {
        return batchQuery(UserPo::getNo, noList);
    }

    @Override
    public UserDto queryByNo(String no) throws ParamException {
        return queryOne(UserPo::getNo, no);
    }

    @Override
    public Collection<UserDto> queryById(Collection<Integer> idList) throws ParamException {
        return batchQuery(UserPo::getId, idList);
    }

    @Override
    public UserDto queryById(Integer id) throws ParamException {
        return queryOne(UserPo::getId, id);
    }

    /**
     * 根据条件删除一条记录
     * @param column
     * @param value
     * @return
     * @throws UserNotExistException
     */
    private UserDto remove(SFunction<UserPo, ?> column, Object value) throws UserNotExistException, ParamException {
        //判断用户是否存在
        UserDto userDto = queryOne(column, value);
        if (userDto == null) {
            throw new UserNotExistException("User not exist.");
        }
        //用户存在则删除
        LambdaQueryWrapper<UserPo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(column, value);
        userMapper.delete(wrapper);
        return userDto;
    }

    @Override
    public UserDto removeById(Integer id) throws UserNotExistException, ParamException {
        return remove(UserPo::getId, id);
    }

    @Override
    public UserDto removeByNo(String no) throws UserNotExistException, ParamException {
        return remove(UserPo::getNo, no);
    }

    @Override
    public UserDto update(UserDto user) throws ParamException, UserNotExistException, UserAlreadyExistException {
        checkParam(user);
        checkParam(user.getId());
        //查询用户是否已存在
        UserPo userPo = userMapper.selectById(user.getId());
        if (userPo == null) {
            throw new UserNotExistException("User not exist.");
        }
        String no = user.getNo();
        String name = user.getName();
        //若允许更新的字段均为空则不更新
        if (StringUtils.isEmpty(no) && StringUtils.isEmpty(name)) {
            return convert(userPo);
        }
        if (StringUtils.isNotEmpty(no)) {
            UserDto userDto = queryByNo(no);
            if(userDto != null && !userDto.getId().equals(user.getId())) {
                throw new UserAlreadyExistException("User not exist.");
            }
            userPo.setNo(no);
        }
        if (StringUtils.isNotEmpty(name)) {
            userPo.setName(name);
        }
        userMapper.updateById(userPo);
        return convert(userPo);
    }

    /**
     * 根据条件修改密码
     * @param column
     * @param value
     * @param password
     * @return
     * @throws ParamException
     * @throws UserNotExistException
     */
    private boolean updatePassword(SFunction<UserPo, ?> column, Object value, String password) throws ParamException, UserNotExistException {
        checkParam(value);
        checkParam(password);
        //查询用户是否已存在
        LambdaQueryWrapper<UserPo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(column, value);
        UserPo userPo = userMapper.selectOne(wrapper);
        if (userPo == null) {
            throw new UserNotExistException("User not exist.");
        }
        userPo.setPassword(password);
        userMapper.updateById(userPo);
        return true;
    }

    @Override
    public boolean updatePasswordById(Integer id, String password) throws UserNotExistException, ParamException {
        return updatePassword(UserPo::getId, id, password);
    }

    @Override
    public boolean updatePasswordByNo(String no, String password) throws UserNotExistException, ParamException {
        return updatePassword(UserPo::getNo, no, password);
    }

    @Override
    public UserDto verifyIdentity(String no, String password) throws UserNotExistException, IncorrectPasswordException {
        LambdaQueryWrapper<UserPo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserPo::getNo, no);
        UserPo userPo = userMapper.selectOne(wrapper);
        if (userPo == null) {
            throw new UserNotExistException("User not exist.");
        }
        if (!userPo.getPassword().equals(password)) {
            throw new IncorrectPasswordException("Incorrect password.");
        }
        return convert(userPo);
    }
}
